package com.dd.cloud.user.service.chknowl.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.constants.ChKnowlConstants;
import com.dd.cloud.common.utils.ExtUtils;
import com.dd.cloud.user.entity.chknowl.ChknowlConsilia;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.user.mapper.chknowl.ChknowlConsiliaMapper;
import com.dd.cloud.user.req.chknowl.*;
import com.dd.cloud.user.res.chknowl.ChknowlConsiliaPageRes;
import com.dd.cloud.user.service.chknowl.IChknowlConsiliaService;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.utils.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 医案 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-07-04
 */
@Service
public class ChknowlConsiliaServiceImpl extends ServiceImpl<ChknowlConsiliaMapper, ChknowlConsilia> implements IChknowlConsiliaService {

    /**
     * word文档导入医案
     *
     * @param file
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importConsiliaWord(MultipartFile file) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();

        String textFileName = file.getOriginalFilename();
        //创建一个map对象存放word中的内容
        Map wordMap = new LinkedHashMap();
        try {
            //判断文件格式
            if (textFileName.endsWith(".doc")) {
                InputStream fis = file.getInputStream();
                //使用HWPF组件中WordExtractor类从Word文档中提取文本或段落
                WordExtractor wordExtractor = new WordExtractor(fis);
                int i = 1;
                //获取段落内容
                for (String words : wordExtractor.getParagraphText()) {
                    System.out.println(words);
                    wordMap.put("DOC文档，第（" + i + "）段内容", words);
                    i++;
                }
                fis.close();
            }
            if (textFileName.endsWith(".docx")) {
                //创建一个临时文件
                File uFile = new File("tempFile.docx");
                if (!uFile.exists()) {
                    uFile.createNewFile();
                }
                //复制文件内容
                FileCopyUtils.copy(file.getBytes(), uFile);
                //包含所有POI OOXML文档类的通用功能，打开一个文件包。
                OPCPackage opcPackage = POIXMLDocument.openPackage("tempFile.docx");

                ChknowlConsilia chknowlConsilia = new ChknowlConsilia();
                //使用XWPF组件XWPFDocument类获取文档内容
                XWPFDocument document = new XWPFDocument(opcPackage);
                List<XWPFParagraph> paras = document.getParagraphs();
                List<XWPFTable> xwpfTables = document.getTables();
                int k = 0;  //目录是否完结
                int j = 1; //目录层级
                int n = 0;  //添加的目录下标
                String first = null;
                StringBuffer sb = new StringBuffer();
                List<String> title = new ArrayList<>();
                int size = paras.size();
                for (int i = 0; i < size; i++) {
                    XWPFParagraph paragraph = paras.get(i);
                    String words = paragraph.getText();
                    if (words.equals("") && i != (size - 1)) {
                        continue;
                    }
                    //目录阶段
                    if (k == 1 && !StringUtils.isBlank(words)) {
                        if (first == null) {
                            //第一个目录
                            if (words.indexOf(" ") >= 0) {
                                words = words.substring(0, words.indexOf(" "));
                            }
                            if (words.indexOf("\t") >= 0) {
                                words = words.substring(0, words.indexOf("\t"));
                            }
                            first = words;
                            title.add(words);
                        } else if (first.equals(words)) {
                            //目录结束, 已经到正文
                            k = -1;
                        } else {
                            j++;
                            //其他目录
                            if (words.indexOf("\t") >= 0) {
                                words = words.substring(0, words.indexOf("\t"));
                            }
                            title.add(words);
                        }
                    }

                    //目录结束, 正文阶段 收集正文内容到目录表
                    if (k == -1) {
                        if (title.indexOf(words) >= 0 || i == (size - 1)) {
                            if (n != 0) {
                                chknowlConsilia.setContent(sb.toString());
                                chknowlConsilia.setStatus(ChKnowlConstants.ContentStatus.NORMAL);
                                chknowlConsilia.setCreateDate(LocalDateTime.now());
//                                chknowlConsilia.setOperId(loginInfo.getId());
//                                chknowlConsilia.setOperDate(LocalDateTime.now());
                                QueryWrapper<ChknowlConsilia> qw = new QueryWrapper<>();
                                qw.lambda().select(ChknowlConsilia::getId)
                                        .eq(ChknowlConsilia::getName, chknowlConsilia.getName())
                                        .ne(ChknowlConsilia::getStatus, ChKnowlConstants.ContentStatus.DELETE);
                                ChknowlConsilia consilia = getOne(qw);
                                if (consilia != null) {
                                    throw new ZekeException(400, "医案名已存在:" + chknowlConsilia.getName());
                                }
                                save(chknowlConsilia);
                                chknowlConsilia = new ChknowlConsilia();
                                sb = new StringBuffer();
                            }

                            chknowlConsilia.setName(words);
                            n++;
                        } else {
                            sb.append(words);
                        }
                    }

                    if (!StringUtils.isBlank(words) && words.equals("目录") && k != -1) {
                        k = 1;
                    }
                }
                uFile.delete();
            }
        } catch (ZekeException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException(500, "word解析失败");
        }

    }

    /**
     * 查询医案内容
     *
     * @param req
     * @return
     */
    @Override
    public IPage<ChknowlConsiliaPageRes> getConsiliaPage(ConsiliaPageReq req) {
        IPage<ChknowlConsiliaPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().getChknowlConsiliaPage(iPage, req);
        return iPage;
    }

    /**
     * 通过id获取医案
     *
     * @param id
     * @return
     */
    @Override
    public ChknowlConsilia getConsiliaById(Integer id) {
        return getById(id);
    }

    /**
     * 添加医案
     *
     * @param req
     */
    @Override
    public void addConsilia(ChknowlConsiliaCreateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        QueryWrapper<ChknowlConsilia> qq = new QueryWrapper<>();
        qq.lambda().select(ChknowlConsilia::getName)
                .eq(ChknowlConsilia::getName, req.getName())
                .ne(ChknowlConsilia::getStatus, ChKnowlConstants.ContentStatus.DELETE);
        ChknowlConsilia chknowlChDrugs = getOne(qq);
        if (chknowlChDrugs != null) {
            throw new ZekeException(400, req.getName() + "医案已存在");
        }
        if (!ObjectUtils.refrect(ChKnowlConstants.ContentStatus.class, req.getStatus())) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        ChknowlConsilia md = new ChknowlConsilia();
        BeanUtils.copyProperties(req, md);

        md.setCreateDate(LocalDateTime.now());
//        md.setOperDate(LocalDateTime.now());
//        md.setOperId(loginInfo.getId());
        boolean flag = save(md);
        if (!flag) {
            throw new ZekeException(400, "添加医案信息失败");
        }
    }

    /**
     * 修改医案
     *
     * @param req
     */
    @Override
    public void updateConsilia(ChknowlConsiliaUpdateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        ChknowlConsilia mpd = getById(req.getId());
        if (mpd == null || mpd.getStatus() == ChKnowlConstants.ContentStatus.DELETE) {
            throw new ZekeException(400, "医案信息不存在");
        }
        if (!mpd.getName().equals(req.getName())) {
            //修改了药品名, 判断药品名是否存在
            QueryWrapper<ChknowlConsilia> qw = new QueryWrapper<>();
            qw.lambda().eq(ChknowlConsilia::getName, req.getName())
                    .select(ChknowlConsilia::getId)
                    .ne(ChknowlConsilia::getStatus, ChKnowlConstants.ContentStatus.DELETE);
            ChknowlConsilia patent = getOne(qw);
            if (patent != null) {
                throw new ZekeException(400, "医案名已存在");
            }
        }
        if (!ObjectUtils.refrect(ChKnowlConstants.ContentStatus.class, req.getStatus())) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        BeanUtils.copyProperties(req, mpd);
//        mpd.setOperId(loginInfo.getId());
//        mpd.setOperDate(LocalDateTime.now());
        boolean flag = updateById(mpd);
        if (!flag) {
            throw new ZekeException(400, "修改医案信息失败");
        }
    }

    /**
     * 修改医案信息状态
     *
     * @param id     id
     * @param status 状态
     */
    @Override
    public void updateChConsiliaStatus(Integer id, Integer status) {
        ChknowlConsilia md = getById(id);
        if (md == null) {
            throw new ZekeException(400, "医案不存在");
        }
        if (!ObjectUtils.refrect(ChKnowlConstants.ContentStatus.class, status)) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        md.setStatus(status);
        boolean flag = updateById(md);
        if (!flag) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
    }

    @Override
    public void importConsiliaBatch(MultipartFile file) {
        if (file == null) {
            throw new ZekeException(400, "请上传文件");
        }
        if (!file.getOriginalFilename().contains(".xlsx") && !file.getOriginalFilename().contains(".xls")) {
            throw new ZekeException(400, "只支持xlsx和xls文件格式");
        }
        List<ExcelAddConsiliaModel> list = new ArrayList<>();
        try {
            list = ExtUtils.importExcel(file, 0, 1, ExcelAddConsiliaModel.class);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ZekeException(400, "解析Excel失败");
        }

        if (list == null || list.isEmpty()) {
            throw new ZekeException(400, "文档数据为空");
        }
        List<ChknowlConsilia> chknowlConsiliaList = new ArrayList<>();
        for (ExcelAddConsiliaModel model : list) {
            ChknowlConsilia chknowlConsilia = new ChknowlConsilia();
            BeanUtils.copyProperties(model, chknowlConsilia);
            chknowlConsilia.setCreateDate(LocalDateTime.now())
                    .setStatus(1);
            chknowlConsiliaList.add(chknowlConsilia);
        }
        if (CollectionUtil.isNotEmpty(chknowlConsiliaList)) {
            Boolean flag = this.saveBatch(chknowlConsiliaList);
            if (!flag) {
                throw new ZekeException("~保存失败~");
            }
        }
    }


}
